﻿
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

using LExperiment.NetworkLib;

namespace LExperiment.LSubscriber
{
    sealed class LSubscriber : IDisposable
    {
        // ************************************************* //
        #region [ member variables ]

        private LTcpChannel m_peerSocket;
        private int m_recvCount;

        private bool m_disposed;

        #endregion

        // ************************************************* //
        #region [ constructor and destructor ]

        ~LSubscriber()
        {
            Dispose(false);
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        private void Dispose(bool isDisposing)
        {
            if (m_disposed)
                return;

            try
            {
                if (isDisposing && m_peerSocket != null)
                {
                    m_peerSocket.Dispose();
                }
            }
            finally
            {
                m_disposed = true;
            }
        }

        #endregion

        // ************************************************* //
        #region [ start point ]

        public void Run(string pubAddress, int pubPort)
        {
            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socket.Connect(NetworkUtility.CreateEndPoint(pubAddress, pubPort));

            // only after the socket is connected, the networkk stream is valid for IO
            m_peerSocket = new LTcpChannel(socket);
            m_peerSocket.BodyRecvedEvtHandler += this.OnBodyRecvedCallback;
            m_peerSocket.PassiveSockClosedEvtHandler += this.OnPassiveSockClosedCallback;

            // launch asynchronous IO operation
            m_peerSocket.BeginReceive();
        }

        #endregion

        // ************************************************* //
        #region [ event operation ]

        private void OnBodyRecvedCallback(object source, BodyRecvEventArgs evtargs)
        {
            string recvString = Encoding.ASCII.GetString(evtargs.Body, 0, evtargs.Body.Length);
            // no need to synchronize this member field, because a new asynchronous read will only be launced after
            // the previous asynchronous read is over, so this member variable will never be shared among multiple threads
            ++m_recvCount;
            Console.WriteLine("<{0}>: {1}", m_recvCount.ToString(), recvString);
        }

        private void OnPassiveSockClosedCallback(object source, EventArgs evtargs)
        {
            Console.Error.WriteLine("!!!!! local socket passively closed !!!!!");
            Environment.Exit(-1);
        }

        #endregion
    }
}